import {
  Directive,
  Input,
  ElementRef,
  Renderer2,
  ViewContainerRef,
  ComponentFactory,
  ComponentFactoryResolver,
  TemplateRef,
  Output,
  EventEmitter,
  OnInit,
  OnChanges,
  OnDestroy,
  SimpleChanges,
  ChangeDetectorRef,
} from '@angular/core';
import { Subject } from 'rxjs';
import { LvConfig } from '../core/config';
import { InputBoolean, InputNumber } from '../core/utils/api';
import { PositionType, ThemeType, TriggerType } from '../core/tooltipbase/api';
import { PopoverComponent } from './popover.component';

@Directive({
  selector: '[lv-popover], [lvPopover]',
  exportAs: 'lvPopover',
})
export class PopoverDirective implements OnChanges, OnInit, OnDestroy {
  @Input('lvPopoverClassName') lvClassName: string; // overlay样式类

  @Input('lvPopoverScrollToClose') lvScrollToClose = true; // 滚动时是否隐藏

  @Input('lvPopoverOuterClosable') lvOuterClosable = true; // 点击overlay外部时是否关闭overlay

  @Input('lvPopoverZIndex') @InputNumber() lvZIndex: number; // 层级

  @Input('lvPopoverTrigger') lvTrigger: TriggerType = 'hover'; // 触发方式

  @Input('lvPopoverPosition') lvPosition: PositionType = 'top'; // 展示位置，默认top，具体设置见POSITION_MAP

  @Input('lvPopoverDisabled') @InputBoolean() lvDisabled = false; // 是否禁用

  @Input('lvPopoverClosable') @InputBoolean() lvClosable = false; // 是否显示关闭按钮

  @Input('lvPopoverOrigin') lvOrigin: ElementRef = this.elementRef; // overlay触发源点

  @Input('lvPopoverHeader') lvHeader: string | TemplateRef<void> = null; // 头部

  @Input('lvPopoverFooter') lvFooter: string | TemplateRef<void> = null; // 底部

  @Input('lvPopoverVisible') @InputBoolean() lvVisible: boolean = false; // 控制overlay是否显示,lvTrigger为customize时生效

  @Input('lvPopoverContent') lvContent: string | TemplateRef<void> = null; // 内容

  @Input('lvPopoverBackdrop') @InputBoolean() lvBackdrop: boolean = false; // 是否显示遮罩层

  @Input('lvPopoverShowArrow') @InputBoolean() lvShowArrow: boolean = true; // 控制overlay小三角是否显示

  @Input('lvPopoverBlockPageScroll') @InputBoolean() lvBlockPageScroll: boolean = true; // 是否锁定页面滚动

  @Input('lvPopoverMaskTransparent') @InputBoolean() lvMaskTransparent: boolean = false; // 遮罩层是否透明

  @Input('lvPopoverAnimationType') lvAnimationType: 'popup' | 'slide' | 'none' = 'popup'; // overlay动画种类，none 为没有动效仅为内部使用

  @Input('lvPopoverTheme') lvTheme: ThemeType = LvConfig.popoverOptions.lvTheme || 'light'; // 主题颜色

  @Input('lvPopoverArrowPointAtCenter') @InputBoolean() lvArrowPointAtCenter: boolean = false;

  @Output('lvPopoverExternalTrigger') lvExternalTrigger: EventEmitter<any> = new EventEmitter(); // 外部触发关闭回调事件

  @Output('lvPopoverVisibleChange') readonly lvVisibleChange: EventEmitter<boolean> = new EventEmitter();

  @Input('lvPopoverAfterOpen') lvAfterOpen: () => (false | void | object) | Promise<false | void | object>; // overlay打开后自定义事件

  @Input('lvPopoverBeforeOpen') lvBeforeOpen: () => (false | void | object) | Promise<false | void | object>; // overlay打开前自定义事件

  @Input('lvPopoverAfterClose') lvAfterClose: () => (false | void | object) | Promise<false | void | object>; // overlay关闭后自定义事件

  @Input('lvPopoverBeforeClose') lvBeforeClose: () => (false | void | object) | Promise<false | void | object>; // overlay关闭前自定义事件

  @Input('lvPopoverContextData') lvContextData: number | string | boolean | Array<any> | { [key: string]: any }; // 内容模板上下文数据

  popoverRef;

  popover: PopoverComponent;

  public destroy$ = new Subject<void>();
  /**
   * 用于动态创建popover组件，
   */
  protected ComponentFactory: ComponentFactory<PopoverComponent> =
    this.resolver.resolveComponentFactory(PopoverComponent);

  protected needProxyProperties = [
    'lvHeader',
    'lvContent',
    'lvFooter',
    'lvIcon',
    'lvTheme',
    'lvTrigger',
    'lvPosition',
    'lvDisabled',
    'lvClosable',
    'lvBackdrop',
    'lvMaskTransparent',
    'lvScrollToClose',
    'lvOuterClosable',
    'lvClassName',
    'lvVisible',
    'lvShowArrow',
    'lvBeforeOpen',
    'lvAfterOpen',
    'lvBeforeClose',
    'lvAfterClose',
    'lvExternalTrigger',
    'lvVisibleChange',
    'lvAnimationType',
    'lvBlockPageScroll',
    'lvOrigin',
    'lvContextData',
    'lvZIndex',
    'lvArrowPointAtCenter',
  ];

  constructor(
    public elementRef: ElementRef,
    protected renderer: Renderer2,
    protected resolver: ComponentFactoryResolver,
    protected ViewContainer: ViewContainerRef,
    protected cdr: ChangeDetectorRef,
  ) {}

  show(): void {
    this.popover.show();
  }

  hide(): void {
    this.popover.hide();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  ngOnInit(): void {
    if (!this.popover) {
      this.createPopoverComponent();
    }
  }

  /**
   * 让组件更新其位置，用于鼠标移动时，改变tips位置
   */
  updatePosition(): void {
    if (this.popover) {
      this.popover.updatePosition();
    }
  }

  removePopoverElement(): void {
    // 删除组件的DOM，因为它应该在overlay容器中。
    if (this.popoverRef?.location?.nativeElement) {
      this.renderer.setStyle(this.popoverRef.location.nativeElement, 'display', 'none');
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    Object.keys(changes).forEach((key): void => {
      if (changes[key]) {
        this.updateComponentProperties(key, changes[key].currentValue);
      }
    });

    this.cdr.markForCheck();
  }

  /**
   * 创建popover组件
   */
  private createPopoverComponent(): void {
    this.popoverRef = this.ViewContainer.createComponent(this.ComponentFactory);
    this.popover = this.popoverRef.instance;
    this.popover.element = this.elementRef.nativeElement;

    this.removePopoverElement();

    // 更新所有属性到组件
    this.needProxyProperties.forEach((property): void => {
      this.updateComponentProperties(property, this[property]);
    });
  }

  /**
   * 更新directive的属性到component
   */
  private updateComponentProperties(key: string, value: any): void {
    if (value !== null || value !== undefined) {
      if (key !== 'lvVisible' && key !== 'lvPosition') {
        this.popover && (this.popover[key] = value);
      } else {
        if (key === 'lvVisible') {
          if (this.popover && value !== this.popover.lvVisible) {
            this.popover.visibleChange(value);
          }
        }

        if (key === 'lvPosition') {
          this.popover?.positionChange(value);
        }
      }
    }
    if (key === 'lvOrigin') {
      this.popover?.updatePositionStrategy();
    }
  }
}
